<template>
  <div @click="savepage" id="12w131">
    <div
      class="dropdown"
      @mouseover="isdropdown = true"
      @mouseleave="isdropdown = false"
    >
      <div
        style="color:white"
        ref="newpagename"
        @click.stop="pageediting"
        :contenteditable="ispageedit && pagename != '最近'"
        @keydown.13.prevent="savepage"
      >
        {{ this.pagename }}
        <i
          v-if="pagename != '最近'"
          class="iconfont icon-close"
          @click.stop="deletepage()"
        ></i>
      </div>
      <div
        v-if="isdropdown"
        :class="{
          'dropdown-content': true,
          'dropdown-cnt': true
        }"
      >
        <div
          v-for="(page, index) in allPageName"
          :key="page + index"
          @click.prevent.stop="chpage(page, index)"
        >
          {{ page }}
        </div>
      </div>
    </div>
    <div
      @dragover="_dragover(-1)"
      @click.left="cancelC"
      @click.right="outermenup(-1)"
      ref="drag_drop"
      @dragstart="remove"
      class="pagecontainer"
    >
      <!-- <transition-group> -->
      <div style="width:100%;height:100%">
        <div
          v-for="(icon, index) in icons"
          :key="index + icon.name"
          draggable="true"
          :class="{
            icon_container: true,
            containerclick: clickindex == index,
            icon_container_hover: hoverindex == index
          }"
          @click.left.stop="changeCurr(index)"
          @click.right.stop="filemenu(index)"
          @mouseenter="hoveron(index)"
          @mouseleave="hovercancel"
          @dragover.stop.prevent="_dragover(index)"
          @dragstart="draghandle(index)"
          @dblclick="open(icon.path)"
        >
          <img :src="icon.src" draggable="false" />
          <!-- use keydown.13.prevent to prevent contenteditable div create div when enter 
        最近 page is difficult to find and update filename,so i prevent this action
        -->
          <div
            spellcheck="false"
            :class="{
              filename: true,
              select: isedit && clickindex == index && pagename != '最近'
            }"
            @keydown.13.prevent
            @keyup.13.prevent="edited(index)"
            :contenteditable="
              isedit && clickindex == index && pagename != '最近'
            "
          >
            {{ icon.name }}
          </div>
        </div>
      </div>
      <!-- </transition-group> -->
    </div>
  </div>
</template>

<script>
import { getNowDateTime, cmp } from "@/utils/common.js";
import { ipcRenderer, clipboard, shell, remote } from "electron";
import DB from "@/utils/db.js";
import { exec } from "child_process";
import fs from "fs";
import path from "path";
import Vue from "vue";
const { Menu, MenuItem } = remote;
const native = require("native");
const unkownicon = path.join(__dirname, "../", "assets", "unknow.png");

let menu = new Menu();
menu.append(
  new MenuItem({
    label: "打开打开新窗口",
    click: function() {
      exec("peony", err => {
        console.log(err);
      });
    }
  })
);
// window.addEventListener("contextmenu", e => {
//   e.preventDefault();
//   menu.popup({ window: remote.getCurrentWindow() });
//   return false;
// });
export default {
  name: "App",
  components: {
    // vuedraggable
  },
  data() {
    return {
      pageremeber: "313",
      pageindex: -1,
      ispageedit: false,
      isdropdown: false,
      allPageName: ["最近"],
      bpath: "",
      pagename: "最近",
      suspendindex: -1,
      //record current dragging ele
      delindex: -1,
      // white bgcolor when renaming
      isedit: false,
      interval: 0,
      clickindex: -1,
      hoverindex: -1,
      icons: []
    };
  },
  methods: {
    deletepage() {
      this.allPageName.splice(this.pageindex, 1);
      this.$layer.msg("删除分类后分类下的所有</br>文件将会恢复到桌面哦");
      exec(
        `mv "${path.join(this.bpath, this.pagename)}" /home/$USER/Desktop/`,
        err => {
          console.log(err);
        }
      );
      DB.deletePage(this.pagename);
      this.pagename = "最近";
    },
    pageediting() {
      this.ispageedit = true;
    },
    savepage() {
      if (this.pagename == "最近") return;
      this.ispageedit = false;
      let newpagename = this.$refs.newpagename.innerText.replace(
        /(^\s*)|(\s*$)/g,
        ""
      );
      if (newpagename === "") {
        newpagename = new Date()
          .getTime()
          .toString()
          .concat("");
        this.$layer.msg("文件名不能为空哦！");
      }
      // if (newpagename == this.pagename) return;
      //update pagename in db
      DB.updatepagename(this.pagename, newpagename);
      //update all files path
      fs.rename(
        path.join(this.bpath, this.pagename),
        path.join(this.bpath, newpagename),
        () => {}
      );
      // this.isdropdown = false;
      Vue.set(this.allPageName, this.pageindex, newpagename);
      // this.isdropdown = true;
      this.pagename = newpagename;
      this.icons.forEach(element => {
        element.path = path.join(this.bpath, newpagename, element.name);
      });
      this.updateFileList();
      this.isdropdown = false;
      this.$forceUpdate();
    },
    chpage(page, index) {
      this.isdropdown = false;
      this.$router.push({
        path: "icon",
        query: {
          pagename: page,
          timestamp: new Date().getTime()
        }
      });
      this.pageindex = index;
    },
    filemenu(index) {
      this.clickindex = index;
      let _that = this;
      let filepath = this.icons[index].path;
      menu = new Menu();
      menu.append(
        new MenuItem({
          label: "打开",
          click() {
            _that.open(filepath);
          }
        })
      );
      let recmendapp = native.get_recommended_open_way(filepath);
      const subm = [];
      for (let i = 0; i < recmendapp.length; i++) {
        let obj = {};
        obj.label = recmendapp[i].app;
        obj.click = function() {
          exec(
            "gtk-launch " +
              recmendapp[i].exec.replace(/%./, "") +
              ` "${filepath}"`,
            err => {
              if (!err) return;
              exec(recmendapp[i].exec.replace(/%./, "") + ` "${filepath}"`);
            }
          );
        };
        subm[i] = obj;
      }
      menu.append(
        new MenuItem({
          label: "打开方式...",
          submenu: subm
        })
      );
      menu.append(
        new MenuItem({
          label: "重命名",
          click() {
            _that.isedit = true;
            _that.clickindex = index;
          }
        })
      );
      menu.append(
        new MenuItem({
          label: "删除...",
          submenu: [
            {
              label: "移入回收站",
              click() {
                shell.moveItemToTrash(filepath);
                _that.icons.splice(index, 1);
                DB.updateDesktopFile(_that.pagename, _that.icons);
              }
            },
            {
              label: "永久删除",
              click() {
                exec("rm -rf" + _that.icons[index], err => {
                  console.log(err);
                });
                _that.icons.splice(index, 1);
                DB.updateDesktopFile(_that.pagename, _that.icons);
              }
            }
          ]
        })
      );
      let cpath = this.icons[this.clickindex].path;
      let cname = this.icons[this.clickindex].name;
      if (fs.statSync(cpath).isDirectory()) {
        menu.append(
          new MenuItem({
            label: "压缩",
            click() {
              ipcRenderer.invoke("userhome").then(home => {
                exec(
                  `engrampa "${cpath}" -a "${home}/Desktop/${cname}.tar.gz" --force `
                );
              });
            }
          })
        );
      }
      menu.append(
        new MenuItem({
          label: "属性",
          click() {
            exec(`peony -p "${_that.icons[index].path}"`);
          }
        })
      );
      menu.popup(remote.getCurrentWindow());
      menu = null;
    },
    //when we choose native file draging api, electron will take over  the whole drag event.That means the ondragend event will not be triggered.And also you can not
    //delete this drag element because this will prevent native drag event when dragging
    //so I use event bubbling principle,add a dragstart event trigger on the parent element.When child triggers native dragstart event,this event will spread
    //to its parent.in its parent's event handle,i delete this item,which function well
    _dragover(index) {
      this.suspendindex = index;
    },
    remove() {
      if (this.pagename == "最近") return;
      this.icons.splice(this.delindex, 1);
      DB.updateDesktopFile(this.pagename, this.icons);
    },
    changeCurr(index) {
      //if the interval between 2 click more than 500 ms,allow user to rename file
      if (this.clickindex == index) {
        let time = new Date().valueOf() - this.interval;
        if (time > 500) {
          this.isedit = true;
        }
      } else {
        this.clickindex = index;
        this.hoverindex = -1;
        this.interval = new Date().valueOf();
        this.isedit = false;
      }
    },
    //when user clicks other position,remove single-click style,and save content
    cancelC() {
      if (this.clickindex == -1) return;
      let Curtname = document.getElementsByClassName("filename")[
        this.clickindex
      ];
      if (!Curtname) return;
      Curtname = Curtname.innerText.replace(/(^\s*)|(\s*$)/g, "");
      if (Curtname === "" || this.haskey(Curtname)) {
        this.$refs.iconname[this.clickindex].innerText = this.icons[
          this.clickindex
        ].name;
        this.clickindex = -1;
        this.isedit = false;
        return;
      } else Vue.set(this.icons[this.clickindex], "name", Curtname);
      //update to database
      DB.updateDesktopFile(this.pagename, this.icons);
      //rename file
      this.rename(this.icons[this.clickindex].path, Curtname);
      this.clickindex = -1;
      this.isedit = false;
    },
    //when mouse enters icon
    hoveron(index) {
      //if  mouse has selected somewhere ,return ;
      if (this.clickindex != -1 && index == this.clickindex) return;
      //otherwises,display hover style
      this.hoverindex = index;
    },
    hovercancel() {
      this.hoverindex = -1;
    },
    //draghander :use ipc to tell main to call native drag method
    draghandle(index) {
      if (this.pagename == "最近") return;
      var event = window.event || arguments.callee.caller.arguments[0];
      event.preventDefault();
      ipcRenderer.send("ondragstart", this.icons[index]);
      this.delindex = index;
    },
    updateFileList() {
      if (this.pagename == "最近") {
        this.icons = DB.getFileSortByTime();
      } else {
        let icons = DB.getFileByPageName(this.pagename);
        if (icons) this.icons = icons.fileDes;
        else this.icons = [];
      }
    },
    //open file
    open(p) {
      if (fs.statSync(p).isDirectory()) {
        exec(`peony -f "${p}"`);
        return;
      }
      if (native.get_type(p) == "application-x-desktop") {
        let exe = native.get_desktop_exec(p);
        exec(exe);
      } else {
        exec(`xdg-open "${p}"`);
      }
    },
    //check whether filename is already used
    haskey(newname) {
      let isexist = false;
      for (let i = 0; i < this.icons.length; i++) {
        console.log("haskey -->" + this.icons[i].name);
        if (this.icons[i].name === newname) {
          isexist = true;
          break;
        }
      }
      return isexist;
    },
    rename(oldpath, newname) {
      let newpath = path.join(path.dirname(oldpath), newname);
      if (native.get_type(oldpath) == "application-x-desktop")
        newpath = newpath + ".desktop";
      this.icons[this.clickindex].path = decodeURI(newpath);
      fs.rename(oldpath, newpath, err => {
        console.log(err);
      });
    },
    move(oldpath, newpath) {
      fs.rename(decodeURI(oldpath), decodeURI(newpath), err => {
        console.log(err);
      });
    },
    edited(index) {
      if (this.clickindex != index) return;
      this.isedit = false;
      //vue binding is not working,and i do not know why,so i choose dom operation  to realize
      //save original name
      var Curtname = document
        .getElementsByClassName("filename")
        [this.clickindex].innerText.replace(/(^\s*)|(\s*$)/g, "");
      if (Curtname === "" || this.haskey(Curtname)) {
        document.getElementsByClassName("filename")[
          this.clickindex
        ].innerText = this.icons[this.clickindex].name;
        this.clickindex = -1;
        console.log("if area --->" + Curtname);
        return;
      } else {
        // Vue.set(this.icons[this.clickindex], "name", Curtname);
        this.icons[this.clickindex].name = Curtname;
        console.log("elsearea --->" + Curtname);
      }
      // rename file
      // this.rename(this.icons[this.clickindex].path, Curtname);
      // cancel clicking style,
      this.clickindex = -1;
      console.log("--------------------------------------");
      // update icons to datebase
      // if (this.pagename != "最近")
      //   DB.updateDesktopFile(this.pagename, this.icons);
    },
    getAllPage() {
      return DB.getAllPage();
    },
    outermenup() {
      menu = new Menu();
      menu.append(
        new MenuItem({
          click() {
            exec("peony $HOME/Desktop", err => {
              if (!err) console.log(err);
            });
          },
          label: "打开新窗口"
        })
      );
      const _that = this;
      //最近 page can support new file action
      if (this.pagename != "最近") {
        menu.append(
          new MenuItem({
            label: "新建...",
            submenu: [
              {
                label: "新建文件",
                click() {
                  let filenamer = path.join(
                    _that.bpath,
                    _that.pagename,
                    "新建文件"
                  );
                  let filename = filenamer;
                  let i = 1;
                  while (fs.existsSync(filename)) {
                    filename = filenamer + "(" + i + ")";
                    i++;
                  }
                  fs.writeFile(filename, "", "utf-8", err => {
                    if (!err) {
                      _that.icons.push({
                        path: filename,
                        src:
                          "file://" + native.get_icon(filename, 48, unkownicon),
                        name: path.basename(filename),
                        createtime: getNowDateTime()
                      });
                      DB.updateDesktopFile(this.pagename, this.icons);
                    }
                  });
                }
              },
              {
                label: "新建文件夹",
                click() {
                  let filenamer = path.join(
                    _that.bpath,
                    _that.pagename,
                    "新建文件夹"
                  );
                  let filename = filenamer;
                  let i = 1;
                  while (fs.existsSync(filename)) {
                    filename = filenamer + "(" + i + ")";
                    i++;
                  }
                  fs.mkdir(filename, err => {
                    if (!err) {
                      _that.icons.push({
                        path: filename,
                        src:
                          "file://" + native.get_icon(filename, 48, unkownicon),
                        name: path.basename(filename),
                        createtime: getNowDateTime()
                      });
                      DB.updateDesktopFile(this.pagename, this.icons);
                    }
                  });
                }
              }
            ]
          })
        );
      }

      menu.append(
        new MenuItem({
          label: "排序方式..",
          submenu: [
            {
              label: "名称",
              click() {
                _that.icons = _that.icons.sort((a, b) => {
                  return a.name - b.name;
                });
              }
            },
            {
              label: "修改时间",
              click() {
                _that.icons = _that.icons.sort((a, b) => {
                  return cmp(
                    fs.statSync(a.path).mtime,
                    fs.statSync(b.path).mtime
                  );
                });
              }
            },
            {
              label: "文件类型",
              click() {
                _that.icons = _that.icons.sort((a, b) => {
                  return path.basename(a.path) - path.basename(b.path);
                });
              }
            },
            {
              label: "文件大小",
              click() {
                _that.icons = _that.icons.sort((a, b) => {
                  return fs.statSync(a.path).size - fs.statSync(b.path).size;
                });
              }
            }
          ]
        })
      );
      menu.append(
        new MenuItem({
          label: "在此处打开终端",
          submenu: [
            {
              label: "以当前用户身份",
              click() {
                exec("mate-terminal --working-directory=$HOME/Desktop", err => {
                  console.log(err);
                });
              }
            },
            {
              label: "以root身份",
              click() {
                ipcRenderer.invoke("userhome").then(home => {
                  exec(
                    `pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY mate-terminal --working-directory=${home}/Desktop`
                  );
                });
              }
            }
          ]
        })
      );
      menu.append(
        new MenuItem({
          label: "新建分类",
          click() {
            let pname = "新建分类";
            let pnamer = pname;
            let i = 1;
            while (_that.allPageName.indexOf(pnamer) != -1) {
              pnamer = pname + i;
              i++;
            }
            _that.allPageName.push(pnamer);
            _that.$router.push({
              path: "icon",
              query: {
                pagename: pnamer,
                timestamp: new Date().getTime()
              }
            });
            DB.insert("desktopclassify", {
              pagename: pnamer,
              fileDes: []
            });
          }
        })
      );
      let filepaths = decodeURI(clipboard.readText());
      let pasteitem = new MenuItem({
        label: "粘贴",
        click() {
          filepaths.split(" ").forEach(filepath => {
            //getting url-encoding text from cliboard
            filepath = filepath.substring(7);
            let src = native.get_icon(filepath, 48, unkownicon);
            let filename = path.basename(filepath);
            let dpath = path.join(_that.bpath, _that.pagename, filename);
            if (filename.endsWith(".desktop"))
              filename = native.get_desktop_name(filepath, filename);
            _that.icons.push({
              src: "file://" + src,
              path: dpath,
              name: filename,
              createtime: getNowDateTime()
            });
            fs.copyFile(filepath, dpath, err => {
              if (!err) clipboard.clear();
            });
          });
          DB.updateDesktopFile(_that.pagename, _that.icons);
        }
      });
      if (filepaths == "" || !filepaths.startsWith("file://")) {
        pasteitem.enabled = false;
      }
      menu.append(pasteitem);
      menu.popup(remote.getCurrentWindow());
      menu = null;
    },
    updatebpath() {
      ipcRenderer.invoke("getFilePath").then(bpath => {
        this.bpath = bpath;
        if (!fs.existsSync(path.join(bpath, this.pagename)))
          fs.mkdir(path.join(bpath, this.pagename), err => {
            console.log(err);
          });
      });
    },
    initdb() {
      this.pagename = this.$route.query.pagename;
      ipcRenderer.invoke("getDataPath").then(storePath => {
        DB.initDB(storePath);
        this.updateFileList();
        this.allPageName = this.getAllPage();
      });
    }
  },
  watch: {
    //watch route.when changing page by queryed param,this will be triggered and update icons.
    $route: function() {
      //change directory path as pagename changes
      this.updatebpath();
      //get page name from queryed param
      this.pagename = this.$route.query.pagename;
      this.pageindex = this.allPageName.length - 1;
      //directory exists but current pagename is not in database
      if (
        !fs.existsSync(path.join(this.bpath, this.pagename)) &&
        this.allPageName.indexOf(this.pagename) == -1
      ) {
        //add pagename to vue data
        this.allPageName.push(this.pagename);
        //add to db
        DB.insert("desktopclassify", { pagename: this.pagename, fileDes: [] });
        //directory does not exist but db has it, create dir
      } else if (
        !fs.existsSync(path.join(this.bpath, this.pagename)) &&
        this.allPageName.indexOf(this.pagename) != -1
      )
        fs.mkdir(path.join(this.bpath, this.pagename), err => {
          console.log(err);
        });
      else if (
        fs.existsSync(path.join(this.bpath, this.pagename)) &&
        this.allPageName.indexOf(this.pagename) == -1
      ) {
        this.allPageName.push(this.pagename);
      }
      //update File list
      this.updateFileList();
    }
  },
  created() {
    //this.pagename = this.$route.params.pagename;
    this.updatebpath();
  },
  mounted() {
    this.initdb();
    this.$refs.drag_drop.ondrop = e => {
      let pagedir = path.join(this.bpath, this.pagename);
      if (this.pagename == "最近") return;
      //get files from drop event
      const files = e.dataTransfer.files;
      //if nothing  drops,return
      if (files.length < 1) return;
      console.log(files);
      for (const file of files) {
        //get file name
        let filename = file.name;
        if (file.name.endsWith(".desktop"))
          filename = native.get_desktop_name(
            file.path,
            path.basename(file.path)
          );

        //get file icon
        let icon = native.get_icon(file.path, 48, unkownicon);
        //get file path
        let filepath = path.join(pagedir, file.name);
        if (this.suspendindex == -1) {
          this.icons.push({
            src: "file://" + icon,
            path: filepath,
            name: filename,
            createtime: getNowDateTime()
          });
        } else {
          this.icons.splice(this.suspendindex, 0, {
            src: "file://" + icon,
            path: filepath,
            name: filename,
            createtime: getNowDateTime()
          });
        }
        //move file from original path to our directron
        this.move(file.path, filepath);
        //when file sequence change ,save to database
        DB.updateDesktopFile(this.pagename, this.icons);
      }
    };
    this.$refs.drag_drop.ondragend = e => {
      e.preventDefault(); //prevent default event handle
    };
    this.$refs.drag_drop.ondragenter = e => {
      e.preventDefault(); //prevent default event handle
    };
    this.$refs.drag_drop.ondragover = e => {
      e.preventDefault(); //prevent default event handle
    };
  }
};
</script>

<style lang="scss">
.bigger {
  font-size: 30px !important;
}

.pagecontainer {
  z-index: 10;
  display: flex;
  width: 100%;
  height: 100%;
}
img {
  width: 80%;
  height: 70%;
}
.select {
  overflow: visible;
  background-color: white;
  user-select: none;
  outline: 1px solid blue;
  cursor: auto !important;
  color: black !important;
}
.containerclick {
  background-color: rgba(60, 117, 191, 0.5);
}
.container {
  display: flex;
  flex: content;
}
.filename {
  max-width: 100%;
  overflow: hidden;
  border: none;
  margin-top: -3px;
  font-family: Arial, "Times New Roman", "Microsoft YaHei", SimHei;
  font: 20px/1em Arial, "Times New Roman", "Microsoft YaHei", SimHei;
  // font-size: 20px;
  height: 39px;
  cursor: default;
  color: white;
}
.icon_container {
  display: inline-block;
  width: 105px;
  height: 129px;
  border-radius: 10%;
  text-align: center;
}
.icon_container_hover {
  background-color: rgba(215, 240, 255, 0.5);
}
.dropdown {
  font-size: 20px;
  display: block;
  text-align: center;
  width: 150px;
  margin: auto;
  position: relative;
}

.dropdown-content {
  color: black;
  display: none;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  // padding: 12px 16px;
  position: absolute;
  border: 1px solid white;
  z-index: 1;
  overflow-y: auto;
}

// .dropdown:hover .dropdown-content {
//   display: block !important;
//   width: 100px;
// }
.dropdown-content div:hover {
  color: #000 !important;
  background-color: rgba(182, 182, 182, 0.3) !important;
}
.dropdown-content div {
  color: white;
}
.dropdown-cnt {
  display: block !important;
  width: 150px;
}
</style>
